package com.crazyhat.crazyhat.service.impl;

import static com.crazyhat.crazyhat.attribute.ApprovalStatusEnum.InReview;
import static com.crazyhat.crazyhat.attribute.ApprovalStatusEnum.Rejected;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.crazyhat.crazyhat.attribute.ApprovalStatusEnum;
import com.crazyhat.crazyhat.attribute.ClubPositionEnum;
import com.crazyhat.crazyhat.attribute.TokenPayloadEnum;
import com.crazyhat.crazyhat.dto.ClubApplicationDTO;
import com.crazyhat.crazyhat.entity.Application;
import com.crazyhat.crazyhat.entity.Club;
import com.crazyhat.crazyhat.entity.Participation;
import com.crazyhat.crazyhat.mapper.ApplicationMapper;
import com.crazyhat.crazyhat.service.IApplicationService;
import com.crazyhat.crazyhat.service.IClubService;
import com.crazyhat.crazyhat.service.IMessageService;
import com.crazyhat.crazyhat.service.IParticipationService;
import com.crazyhat.crazyhat.utils.ThreadLocalUtil;
import com.github.yulichang.query.MPJQueryWrapper;


/**
 * <p>
 * 社团申请 服务实现类
 * </p>
 *
 * @author crazyhat
 * @since 2024-07-05
 */
@Service
public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Application> implements IApplicationService {

    /**
     * 再次申请间隔时间，单位：Minutes
     */
    private final long intervalReapply=30;

    @Autowired
    private ApplicationMapper applicationMapper;

    @Autowired
    private IClubService clubService;

    @Autowired
    private IParticipationService participationService;

    @Autowired
    private IMessageService messageService;

    @Override
    public ApprovalStatusEnum joinClub(Integer joinClubId) {

        if (clubService.clubJoinable(joinClubId)) {

            /*
             * 若社团可加入
             */

            Map<String,Object> map=ThreadLocalUtil.get();
            Integer studentId=(Integer)map.get(TokenPayloadEnum.StudentId.getValue());

            if (participationService.hasParticipation(joinClubId,studentId)) {

                /*
                 * 若用户已加入该社团，返回“已接受”
                 */

                return ApprovalStatusEnum.Accepted;
            }

            /*
             * 判断用户对社团的申请状态
             */
            Application application=this.getApplicationForClub(joinClubId,studentId);
            if (application!=null) {

                /**
                 * 若已存在对该社团的申请
                 */

                if (application.getApprovalStatus().equals(ApprovalStatusEnum.InReview)) {

                    /*
                     * 若已经存在的申请状态为“审核中”
                     */

                    if (this.canApplyAgain(application)) {
                        /*
                         * 若可再次申请，更新申请时间
                         */
                        application.setApplyTime(LocalDateTime.now());

                        applicationMapper.updateById(application);

                        participationService.getClubManagerList(joinClubId).forEach((item)->{
                            if (item!=null) {
                                messageService.sendMessageToStudent(item.getStudentId(), joinClubId, "社团有加入申请待审核");
                            }
                        });
                    }
                }

                return application.getApprovalStatus();
            }

            /*
             * 创建新申请
             */
            Application newApplication=new Application();
            newApplication.setClubId(joinClubId);
            newApplication.setStudentId(studentId);
            newApplication.setApplyTime(LocalDateTime.now());
            newApplication.setApprovalStatus(ApprovalStatusEnum.InReview);

            applicationMapper.insert(newApplication);

            /**
             * 创建新申请成功，返回“审核中”
             */

            participationService.getClubManagerList(joinClubId).forEach((item) -> {
                if (item != null) {
                    messageService.sendMessageToStudent(item.getStudentId(), joinClubId, "社团有新的加入申请，请尽快审核");
                }
            });

            return newApplication.getApprovalStatus();

        } else {

            /**
             * 社团不可加入，返回“被拒绝”
             */

            return ApprovalStatusEnum.Rejected;
        }
    }

    /**
     * 查询用户对社团的申请
     * @param joinClubId
     * @param studentId
     * @return
     */
    private Application getApplicationForClub(Integer joinClubId,Integer studentId) {

        QueryWrapper<Application> queryWrapper=new QueryWrapper<>();
        queryWrapper
            .eq("student_id", studentId)
            .eq("club_id", joinClubId);

        return applicationMapper.selectOne(queryWrapper);
    }


    /**
     * 判断是否可再次申请
     * @param application
     * @return
     */
    private boolean canApplyAgain(Application application) {

        if (application ==null ) {
            return false;
        }

        /**
         * 获取申请已过时间
         */
        Duration duration=Duration.between(application.getApplyTime(), LocalDateTime.now());

        if (Math.abs(duration.toMinutes()) >= this.intervalReapply) {
            return true;
        }

        return false;
    }

    /*
    * 审核加入申请
    * */
    @Override
    public boolean checkApplication(Integer applicationId, boolean approve){

        Application application = applicationMapper.selectById(applicationId);
        if (application == null) {
            return false;
        }
        //资格审查
        if(!(participationService.isCommunityManager(application.getClubId())))
            return false;

        //被审核过了
        if(!InReview.equals(application.getApprovalStatus())){
            return false;
        }

        boolean insertResult=false;
        Participation participation1=new Participation();
        if (approve) {
            //从application中获得用户id并将用户加入到社团
            participation1.setClubId(application.getClubId());
            participation1.setStudentId(application.getStudentId());
            participation1.setParticipateTime(LocalDateTime.now());
            participation1.setClubPosition(ClubPositionEnum.MEMBER);
            insertResult=participationService.save(participation1);

            application.setApprovalStatus(ApprovalStatusEnum.Accepted);

        } else {
            application.setApprovalStatus(Rejected);
        }

        Club club=clubService.selectById(application.getClubId());
        // 发送消息给申请人
        String content = "您申请加入"+club.getClubName()+"社团的请求"+(approve ? "已通过审核。" : "被拒绝。");
        messageService.sendMessageToStudent(application.getStudentId(), application.getClubId(), content);

        // 删除或标记处理后的消息
        applicationMapper.updateById(application);
        return insertResult;
    }

    /*
    * 查看申请信息
    * */
    @Deprecated
    @Override
    public Page<Application> examineApplication(int pageNum, int pageSize) {
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer studentId = (Integer) map.get(TokenPayloadEnum.StudentId.getValue());

        //根据学号到participation表中查看自己是哪些社团的一把手或二把手
        QueryWrapper<Participation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("student_id", studentId)
                .and(wrapper -> wrapper
                        .eq("club_position", "一把手")
                        .or()
                        .eq("club_position", "二把手")
                )
                .select("club_id");

        List<Participation> participation = participationService.selectList(queryWrapper);
        // 提取 club_id 字段，存到一个List里
        List<Integer> clubIds = participation.stream()
                .map(Participation::getClubId)
                .collect(Collectors.toList());

        //不是一把手或二把手，返回一个空的查询结果
        if(clubIds.isEmpty()){
            Page<Application> emptyPage = new Page<>(pageNum, pageSize);
            emptyPage.setTotal(0);
            emptyPage.setRecords(new ArrayList<>());
            return emptyPage;
        }
        //到application表中查找对应社团的申请信息
        QueryWrapper<Application> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.in("club_id", clubIds);
        // 创建分页对象
        Page<Application> page = new Page<>(pageNum, pageSize);

        // 分页查询
        return applicationMapper.selectPage(page, queryWrapper1);
    }

    /**
     * 获取个人申请列表
     */
    @Deprecated
    @Override
    public Page<Application> personalApplication(int pageNum, int pageSize) {
        // 获取当前用户ID
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer studentId = (Integer) map.get("studentId");
        QueryWrapper<Application> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("student_id", studentId);

        // 创建分页对象
        Page<Application> page = new Page<>(pageNum, pageSize);

        // 分页查询
        return applicationMapper.selectPage(page, queryWrapper);
    }


    @Override
    public Page<Application> selectPage(Page<Application> page, QueryWrapper<Application> queryWrapper) {
        return applicationMapper.selectPage(page,queryWrapper);
    }

    /**
     * 获取社团的加入申请列表
     */
    @Override
    public List<ClubApplicationDTO> getApplicationList(Integer clubId,boolean getAll) {

        if(clubId==null){
            return null;
        }

        if (!(participationService.isCommunityManager(clubId))) {

            //如果非社团管理员
            return null;
        }

        MPJQueryWrapper<Application> mpjQueryWrapper=new MPJQueryWrapper<>();
        mpjQueryWrapper
            .selectAll(Application.class)
            .select("u.name","u.avatar_url")
            .leftJoin("user u on u.student_id = t.student_id")
            .eq("t.club_id",clubId);

        if (!getAll) {
            mpjQueryWrapper.eq("t.approval_status",ApprovalStatusEnum.InReview);
        }

        List<ClubApplicationDTO> applicationList=applicationMapper.selectJoinList(ClubApplicationDTO.class, mpjQueryWrapper);

        return applicationList;

    }
}
